home *** CD-ROM | disk | FTP | other *** search
/ L' Effet Pommier 3 / L'Effet Pommier - Volume 03.iso / Programmation / gray image 2.1 / vimage.cc < prev    next >
Text File  |  1995-05-30  |  29KB  |  884 lines

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /*
  3.  ************************************************************************
  4.  *
  5.  *               Grayscale Image
  6.  *
  7.  *      Verify the class image member functions and friends
  8.  *
  9.  * $Id: vimage.cc,v 2.0 1995/03/18 18:45:04 oleg Exp oleg $
  10.  *
  11.  ************************************************************************
  12.  */
  13.  
  14. #include "image.h"
  15. #include "std.h"
  16. #include <iostream.h>
  17. #include <minmax.h>
  18.  
  19. static IMAGE Test_image(16,32,8); //(256,512,8);
  20.  
  21.  
  22. /*
  23.  *----------------------------------------------------------------------
  24.  *        Testing primitive operations and inquires
  25.  */
  26.  
  27. static void test_primitive(void)
  28. {
  29.   cout << "\n\nTest primitive image operations and inquires\n";
  30.   
  31.   IMAGE image(Test_image);
  32.   cout << "\nInquires for the image like Test image";
  33.   cout << "\nNo of rows      " << image.q_nrows();
  34.   cout << "\nNo of cols      " << image.q_ncols();
  35.   cout << "\nDepth           " << image.q_depth();
  36.   cout << "\nTotal no pixels " << image.q_npixels();
  37.   cout << "\nName       '" << image.q_name() << "'";
  38.  
  39.   cout << "\nThe following line is returned by image.info()\n";
  40.   image.info();
  41.  
  42.   assert( image.q_npixels() == image.q_ncols() * image.q_nrows() );
  43.  
  44.   cout << "\nDone\n\n";
  45. }
  46.  
  47.                 // Verify the rowcol class
  48. static void test_rowcol(void)
  49. {
  50.   cout << "\n\nTest the rowcol class and operations on it\n";
  51.  
  52.   const int row_const = 5, col_const = 32005;
  53.  
  54.   {
  55.     cout << "\tVerify constructing the rowcol object from two integers\n";
  56.     rowcol pos1(row_const,col_const);
  57.     assert( pos1.row() == row_const && pos1.col() == col_const );
  58.   }
  59.  
  60.   {
  61.     cout << "\tVerify assignment operations\n";
  62.     rowcol pos1(row_const,col_const);
  63.     rowcol pos2(-1,-1);
  64.     assert( pos2.row() != row_const && pos2.col() != col_const );
  65.     pos2 = pos1;
  66.     assert( pos2.row() == row_const && pos2.col() == col_const );
  67.     rowcol pos3(pos2);
  68.     assert( pos3.row() == row_const && pos3.col() == col_const );
  69.     pos3 = rowcol(col_const,row_const);
  70.     assert( pos3.col() == row_const && pos3.row() == col_const );
  71.   }
  72.  
  73.   {
  74.     cout << "\tVerify comparisons\n";
  75.     rowcol pos1(row_const,col_const);
  76.     rowcol pos2(-1,-1);
  77.     assert( !(pos2 == pos1) );
  78.     pos2 = pos1;
  79.     assert( pos2 == pos1 );
  80.     assert( pos2 == rowcol(row_const,col_const) );
  81.     rowcol pos4(row_const,0);
  82.     assert( !(pos4 == pos1) );
  83.     rowcol pos5(0,col_const);
  84.     assert( !(pos5 == pos1) );
  85.   }
  86.  
  87.   {
  88.     cout << "\tVerify shifting and offsetting operations\n";
  89.     rowcol pos1(row_const,col_const);
  90.     rowcol pos2(pos1);
  91.     assert( pos1 == pos2 );
  92.  
  93.     assert( (pos1-pos2) == rowcol(0,0) );
  94.     assert( pos1 == pos2 );
  95.     pos1 -= pos2;
  96.     assert( pos1 == rowcol(0,0) );
  97.     assert( pos2 == rowcol(row_const,col_const) );
  98.  
  99.     assert( (pos1+pos2) == pos2 );
  100.     assert( !(pos1 == pos2) );
  101.     pos1 += pos2;
  102.     assert( pos1 == pos2 );
  103.  
  104.     assert( (pos1-rowcol(row_const,0)) == rowcol(0,col_const) );
  105.     pos1 -= rowcol(row_const,0);
  106.     assert( pos1 == rowcol(0,col_const) );
  107.     pos1 += rowcol(0,1);
  108.     assert( pos1 == rowcol(0,col_const+1) );
  109.     pos2 -= pos1;
  110.     assert( pos2 == rowcol(row_const,-1) );
  111.     assert( (pos1+pos2) == rowcol(row_const,col_const) );
  112.     pos1 += pos2;
  113.     assert( pos1 == rowcol(row_const,col_const) );
  114.   }
  115.  
  116.   {
  117.     cout << "\tVerify scaling operations\n";
  118.     rowcol pos1(4,5);
  119.     rowcol pos2(pos1);
  120.     pos1 *= 1;
  121.     assert( pos1 == pos2 );
  122.     pos1 *= 4;
  123.     assert( pos1 == pos2 * 4 );
  124.     assert( pos1 == pos2 << 2 );
  125.     assert( pos1 >> 2 == pos2 );
  126.     pos2 += pos2;
  127.     pos2 += pos2;
  128.     assert( pos1 == pos2 );
  129.  
  130.   }
  131.  
  132.   cout << "\nDone\n\n";
  133. }
  134.  
  135. /*
  136.  *----------------------------------------------------------------------
  137.  *        Testing reading/writing a pixel and pixel modifications
  138.  */
  139.  
  140.  
  141. static void test_pixel_op()
  142. {
  143.   const int pattern = 145;
  144.   register int i,j;
  145.  
  146.   cout << "\n\nTest reading/writing pixels and pixel modifications\n";
  147.  
  148.   cout << "Writing zeros ...\n";
  149.   for(i=0; i<Test_image.q_nrows(); i++)
  150.     for(j=0; j<Test_image.q_ncols(); j++)
  151.       Test_image(i,j) = 0;
  152.  
  153.   verify_pixel_value(Test_image,0);
  154.   assert( Test_image == 0 );
  155.  
  156.   cout << "Writing a pattern 0x" << hex << pattern << dec << "...\n";
  157.   for(i=0; i<Test_image.q_nrows(); i++)
  158.     for(j=0; j<Test_image.q_ncols(); j++)
  159.       Test_image(rowcol(i,j)) = pattern;
  160.  
  161.   verify_pixel_value(Test_image,pattern);
  162.   assert( Test_image == pattern );
  163.   assert( Test_image >  0 && Test_image >= pattern );
  164.   assert( !(Test_image ==  0) && Test_image != 0 );
  165.   assert( Test_image > pattern-1 && Test_image >= pattern-1 );
  166.   assert( Test_image < pattern+1 && Test_image <= pattern+1 );
  167.   assert( Test_image <= pattern && !(Test_image < pattern) );
  168.   assert( Test_image >= pattern && !(Test_image > pattern) );
  169.  
  170.   cout << "Inverting the image, the pattern has to turn to " << 
  171.     hex << 0xff - pattern << "...\n";
  172.   Test_image.invert();
  173.   verify_pixel_value(Test_image,0xff - pattern);
  174.  
  175.   cout << "Clearing the image ...\n";
  176.   Test_image.clear();
  177.   verify_pixel_value(Test_image,0);
  178.   assert( Test_image < pattern && Test_image <= pattern );
  179.  
  180.   const int test_val = 0x7e;
  181.   cout << "Assigning the value " << hex << test_val 
  182.        << " to all the pixels...\n" << dec;
  183.   Test_image = test_val;
  184.   verify_pixel_value(Test_image,test_val);
  185.  
  186.   cout << "Adding three...\n";
  187.   Test_image += 3;
  188.   verify_pixel_value(Test_image,test_val+3);
  189.   assure( Test_image > 0, "Negative pixel unexpected");
  190.  
  191.   cout << "Subtracting " << 2*test_val << "...\n";
  192.   Test_image -= 2*test_val;
  193.   verify_pixel_value(Test_image,test_val+3-2*test_val);
  194.   assure( Test_image < 0, "Non-Negative pixel unexpected");
  195.  
  196.   cout << "Subtracting " << -2*test_val+3 << "...\n";
  197.   Test_image -= -2*test_val+3;
  198.   verify_pixel_value(Test_image,test_val);
  199.  
  200.   cout << "Set two lowest bits\n";
  201.   Test_image |= 0x03;
  202.   verify_pixel_value(Test_image,test_val | 0x03);
  203.  
  204.   cout << "Reset two lowest bits\n";
  205.   Test_image &= 0xff - 0x03;
  206.   verify_pixel_value(Test_image,test_val & (0xff - 0x03));
  207.  
  208.   cout << "Set the 2nd bit with XOR\n";
  209.   Test_image ^= 0x02; 
  210.   verify_pixel_value(Test_image,test_val);
  211.  
  212.   cout << "Multiply by 2\n";
  213.   Test_image *= 2; 
  214.   verify_pixel_value(Test_image,2*test_val);
  215.  
  216.   cout << "Multiply by 2 once more by shifting to the left\n";
  217.   Test_image <<= 1; 
  218.   verify_pixel_value(Test_image,4*test_val);
  219.  
  220.   cout << "Divide by 4 by shifting to the right\n";
  221.   Test_image >>= 2; 
  222.   verify_pixel_value(Test_image,test_val);
  223.  
  224.   cout << "If image >=0, then abs(image) should coincide with itself\n";
  225.   assert( Test_image >= 0 );
  226.   Test_image.abs();
  227.   verify_pixel_value(Test_image,test_val);
  228.  
  229.   cout << "Assign image = -test_val and test image.abs()\n";
  230.   Test_image -= 2*test_val;
  231.   assert( Test_image < 0 );
  232.   Test_image.abs();
  233.   verify_pixel_value(Test_image,test_val);
  234.   
  235.   {
  236.     cout << "Assign image = -test_val and test image.apply(abs)\n";
  237.     Test_image -= 2*test_val;
  238.     assert( Test_image < 0 );
  239.     class AbsImage : public PixelPrimAction {
  240.       void operation(GRAY& pixel) { pixel = abs((GRAY_SIGNED)pixel); }
  241.       public: AbsImage(void) {}
  242.     };
  243.     Test_image.apply(AbsImage());
  244.     verify_pixel_value(Test_image,test_val);
  245.   }
  246.  
  247.   cout << "Assign image = -test_val and put down all negative pixels\n";
  248.   Test_image -= 2*test_val;
  249.   assert( Test_image < 0 );
  250.   Test_image.clip_to_intensity_range();
  251.   verify_pixel_value(Test_image,0);
  252.  
  253.   cout << "Assign image = max_val+test_val and clip to the intensity region\n";
  254.   Test_image = test_val;
  255.   Test_image.clip_to_intensity_range();
  256.   verify_pixel_value(Test_image,test_val);
  257.   Test_image += (1<<Test_image.q_depth())-1;
  258.   Test_image.clip_to_intensity_range();
  259.   verify_pixel_value(Test_image,(1<<Test_image.q_depth())-1);
  260.  
  261.   {
  262.     cout << "Check to see that PixelAction are executed row-wise" << endl;
  263.     class assign_pixels : public PixelAction {
  264.       const card test_im_nrows, test_im_ncols;
  265.       void operation(GRAY& pixel)
  266.       {
  267.     assert(nrows == test_im_nrows);
  268.     assert(ncols == test_im_ncols);
  269.     pixel = col + row*ncols;
  270.       }
  271.     public: assign_pixels(const IMAGE& im) : 
  272.       test_im_nrows(im.q_nrows()), test_im_ncols(im.q_ncols()) {}
  273.     };
  274.     Test_image.apply(assign_pixels(Test_image));
  275.  
  276.     class check_pixels : public PixelPrimAction {
  277.       GRAY curr_value;
  278.       void operation(GRAY& pixel) { assert(pixel == curr_value++); }
  279.       public: check_pixels(void) : curr_value(0) {}
  280.     };
  281.     Test_image.apply(check_pixels());
  282.   }
  283.   cout << "\nDone\n\n";
  284. }
  285.  
  286. static void test_image_op()
  287. {
  288.   const int pattern = 144;
  289.  
  290.   cout << "\n\nTest binary image operations and comparisons\n";
  291.   cout << "Pattern value being used " << pattern <<
  292.                             " (0x" << hex << pattern << dec << ")\n";
  293.  
  294.   cout << "Allocation with assignment\n";
  295.   Test_image = pattern;
  296.   IMAGE im2 = Test_image; im2 = Test_image;
  297.   assure(Test_image == im2, "Non-identical images");
  298.  
  299.   cout << "Assignment of one image to the other\n";
  300.   im2 += pattern;
  301.   Test_image = im2;
  302.   assure(Test_image==im2, "Non-identical images");
  303.   verify_pixel_value(Test_image,2*pattern);
  304.  
  305.   cout << "Subtraction of two images\n";
  306.   im2 = pattern;
  307.   Test_image -= im2;
  308.   assure(Test_image==im2, "Non-identical images");
  309.   verify_pixel_value(Test_image,pattern);
  310.   assert(Test_image == pattern);
  311.   
  312.   cout << "Addition of images\n";
  313.   Test_image += im2;
  314.   assure(!(Test_image==im2), "Identical images unexpected");
  315.   verify_pixel_value(Test_image,2*pattern);
  316.  
  317. #if 0  
  318.   cout << "Addition of images through add() function\n";
  319.   add(Test_image,2,im2);
  320.   assure(!(Test_image==im2), "Identical images unexpected");
  321.   verify_pixel_value(Test_image,4*pattern);
  322.   
  323.   cout << "Subtraction of images through add() function\n";
  324.   add(Test_image,-3,im2);
  325.   assure(Test_image==im2, "Non-identical images");
  326.   verify_pixel_value(Test_image,pattern);
  327.  
  328.   cout << "Double only one pixel,(5,6), and perform operations to triple it\n";
  329.   Test_image(5,6) *= 2;
  330.   Test_image += im2;
  331.   add(Test_image,-3,im2);
  332.   Test_image += Test_image;
  333.   add(Test_image,3,im2);
  334.   compare(Test_image,im2,"Image with one pixel different and original");
  335. #endif
  336.  
  337.   cout << "Subtracting the image from itself\n";
  338.   Test_image -= Test_image;
  339.   verify_pixel_value(Test_image,0);
  340.  
  341.   cout << "Set two lower bits\n";
  342.   Test_image = pattern; im2 = 0x03;
  343.   Test_image |= im2;
  344.   verify_pixel_value(Test_image,pattern | 0x03);
  345.  
  346.   cout << "Reset two lowest bits\n";
  347.   im2.invert();
  348.   Test_image &= im2;
  349.   verify_pixel_value(Test_image,pattern & (0xff - 0x03));
  350.  
  351.   cout << "Set the 2nd bit with XOR\n";
  352.   im2 = 0x02;
  353.   Test_image ^= im2;
  354.   verify_pixel_value(Test_image,pattern | 0x02);
  355.  
  356.   cout << "OR with 0x13 followed by AND with 0x6d for non-uniform image\n";
  357.   Test_image = pattern; Test_image(4,5) += 5;
  358.   im2 = 0x13; Test_image |= im2; im2.invert(); Test_image &= im2;
  359.   im2 = pattern; im2(4,5) += 5;
  360.   im2 |= 0x13; im2 &= ~(0x13);
  361.   assure(Test_image == im2,"Pixel-by-pixel and image-by-image produced"
  362.      "different results");
  363.   
  364.   cout << "XORing the image with itself\n";
  365.   Test_image ^= Test_image;
  366.   verify_pixel_value(Test_image,0);
  367.  
  368. #if 0
  369.   cout << "Add two images through shift_clip_add\n";
  370.   Test_image = pattern;
  371.   Test_image.shift_clip_add(rowcol(0,0),1,Test_image);
  372.   verify_pixel_value(Test_image,2*pattern);
  373.   im2 = pattern;
  374.   Test_image.shift_clip_add(rowcol(0,0),-2,im2);
  375.   verify_pixel_value(Test_image,0);
  376.  
  377.   {
  378.     cout << "Change a single pixel through shift_clip_add\n";
  379.     Test_image = 2*pattern;
  380.     im2 = pattern;
  381.     rowcol rightbottom(Test_image.q_nrows()-1,Test_image.q_ncols()-1);
  382.     Test_image(rightbottom) += pattern;           // Increment a pixel
  383.     assert( !(Test_image == 2*pattern) && !(Test_image != 2*pattern) );
  384.     Test_image.shift_clip_add(rightbottom,-1,im2); // and decrement it back
  385.     verify_pixel_value(Test_image,2*pattern);           // in the other way
  386.     assert( Test_image == 2*pattern );
  387.  
  388.   {
  389.     Test_image(0,0) -= pattern;
  390.     assert( !(Test_image == 2*pattern) && !(Test_image != 2*pattern) );
  391.     rowcol pos = rightbottom * (-1);
  392.     Test_image.shift_clip_add(pos,1,im2);
  393.     // Test_image.shift_clip_add(rightbottom * (-1),1,im2);
  394.     verify_pixel_value(Test_image,2*pattern);
  395.     assert( Test_image == 2*pattern );
  396.   }
  397.   }
  398.   
  399.   {
  400.     cout << "Change a bottom right quadrant through shift_clip_add\n";
  401.     Test_image = 2*pattern;
  402.     im2 = pattern;
  403.     rowcol rightbottom(Test_image.q_nrows()-1,Test_image.q_ncols()-1);
  404.     rowcol center(Test_image.q_nrows()/2,Test_image.q_ncols()/2);
  405.     Test_image.rectangle(center,rightbottom) -= 2*pattern; // Decrement a block
  406.     assert( !(Test_image == 2*pattern) && !(Test_image != 2*pattern) );
  407.     Test_image.shift_clip_add(center,2,im2);     // and increment it back
  408.     verify_pixel_value(Test_image,2*pattern);           // in the other way
  409.     assert( Test_image == 2*pattern );
  410.   }
  411.  
  412.   {
  413.     cout << "Change a part of the image through shift_clip_add\n";
  414.     Test_image = 3*pattern;
  415.     rowcol pos1(4,5);
  416.     rowcol pos2(Test_image.q_nrows()-2,Test_image.q_ncols()-3);
  417.     IMAGE im3 = Test_image.rectangle(pos1,pos2);
  418.     Test_image.rectangle(pos1,pos2) -= 3*pattern; // Decrement a block
  419.     assert( !(Test_image == 3*pattern) && !(Test_image != 3*pattern) );
  420.     assert( im3 == 3*pattern );
  421.     Test_image.shift_clip_add(pos1,1,im3);        // and increment it back
  422.     verify_pixel_value(Test_image,3*pattern);           // in the other way
  423.     assert( Test_image == 3*pattern );
  424.   }
  425. #endif
  426.  
  427.   cout << "\nDone\n\n";
  428. }
  429.  
  430. /*
  431.  *------------------------------------------------------------------------
  432.  *        Testing norm and scalar product calculations
  433.  */
  434.  
  435. static void test_scalar_product()
  436. {
  437.   const int pattern = 145;
  438.  
  439.   cout << "\n\nTest the computation of the scalar product of two images\n";
  440.   cout << "Pattern value being used " << pattern;
  441.  
  442.   int dim = (max(Test_image.q_nrows(),Test_image.q_ncols()) >> 1) << 1;
  443.   IMAGE imt(dim,dim,8), ims(dim,dim,8);
  444.  
  445.   cout << "\nSquare image of size " << dim << " is being tested";
  446.   cout << "\nTesting by making the Haar (+ - - +) function and checking\n" 
  447.           "its orthogonality with other Haar functions";
  448.  
  449.                 // Make the Haar (+ - - +) function
  450.   ims.square_of(dim/2,rowcol(0,0))         = pattern;
  451.   ims.square_of(dim/2,rowcol(0,dim/2))         = -pattern;
  452.   ims.square_of(dim/2,rowcol(dim/2,0))         = -pattern;
  453.   ims.square_of(dim/2,rowcol(dim/2,dim/2))     = pattern;
  454.   assert( ims != 0 && !(ims == 0) && !(ims == pattern) && !(ims != pattern) );
  455.   assert( !(ims >= pattern) && ims >= -pattern && ims <= pattern );
  456.   assert( !(ims > 0) && !(ims < 0) );
  457.     
  458.  
  459.   cout << "\nsum over ims " << sum_over(ims.square_of(dim,rowcol(0,0)));
  460.  
  461.   imt = pattern;
  462.   cout << "\n Scalar product with Haar (+ + + +) function is " << ims * imt;
  463.  
  464.   imt.square_of(dim/2,rowcol(0,0))         = -pattern;
  465.   imt.square_of(dim/2,rowcol(0,dim/2))         = -pattern;
  466.   imt.square_of(dim/2,rowcol(dim/2,0))         = pattern;
  467.   imt.square_of(dim/2,rowcol(dim/2,dim/2))     = pattern;
  468.   cout << "\n Scalar product with Haar (- - + +) function is " << imt * ims;
  469.  
  470.   imt.square_of(dim/2,rowcol(0,0))         = -pattern;
  471.   imt.square_of(dim/2,rowcol(0,dim/2))         = pattern;
  472.   imt.square_of(dim/2,rowcol(dim/2,0))         = -pattern;
  473.   imt.square_of(dim/2,rowcol(dim/2,dim/2))     = pattern;
  474.   cout << "\n Scalar product with Haar (- + - +) function is " << ims * imt;
  475.  
  476.   imt = ims;
  477.   cout << "\n Scalar product with Haar (+ - - +) function is " << imt * ims;
  478.   cout << "\n Theoretical value                     " 
  479.        << sqr(pattern * dim);
  480.   assure( imt * ims == sqr(pattern * dim), "There is discrepancy!" );
  481.  
  482.   cout << "\nDone\n\n";
  483. }
  484.  
  485. static void test_image_norms(void)
  486. {
  487.   const int pattern = 154;
  488.  
  489.   cout << "\n\nTest image norm computations\n";
  490.  
  491.   Test_image.clear();
  492.  
  493.   cout << "\nInitializing the image with the pattern " << pattern << "...\n";
  494.   Test_image = pattern;
  495.  
  496.   cout << "\tChecking out the 1. image norm, which should be "
  497.        << pattern * (double)Test_image.q_npixels() << "\n";
  498.   assert( Test_image.norm_1() == pattern * (double)Test_image.q_npixels() );
  499.   cout << "\tChecking out the 2. image norm, which should be "
  500.        << pattern * pattern * (double)Test_image.q_npixels() << "\n";
  501.   assert( Test_image.norm_2_sqr() ==
  502.       sqr(pattern) * (double)Test_image.q_npixels() );
  503.   cout << "\tChecking out the 2. image norm is equal to the scalar product\n"
  504.           "\t\tof the image with itself\n";
  505.   assert( Test_image.norm_2_sqr() == Test_image * Test_image );
  506.   cout << "\tChecking out the inf image norm is equal to the pattern itself\n";
  507.   assert( Test_image.norm_inf() == pattern );
  508.  
  509.   cout << "\nInitializing the image with the pattern " << pattern << 
  510.           "\n with a quater of it being set to " << -2*pattern << "\n";
  511.   Test_image = pattern;
  512.   int size = min(Test_image.q_ncols(),Test_image.q_nrows())/2;
  513.   Test_image.square_of(size,rowcol(0,0)) = -2*pattern;
  514.   assert( !(Test_image == pattern) && !(Test_image != pattern) );
  515.   assert( Test_image <= pattern && Test_image >= -2*pattern );
  516.   assert( !(Test_image > 0) && !(Test_image < 0) && Test_image != 0 );
  517.  
  518.   cout << "\tChecking out the 1. image norm\n";
  519.   assert( Test_image.norm_1() == pattern * (double)Test_image.q_npixels() 
  520.       + pattern * size * size );
  521.   {
  522.     IMAGE im(Test_image);
  523.     im = Test_image;
  524.     im.abs();
  525.     assert( im.norm_1() == Test_image.norm_1() );
  526.   }
  527.  
  528.   cout << "\tChecking out the 2. image norm\n";
  529.   assert( Test_image.norm_2_sqr() ==
  530.       sqr(pattern) * (double)Test_image.q_npixels() + 
  531.       3 * sqr(pattern) * sqr(size) );
  532.   {
  533.     IMAGE im(Test_image); IMAGE im1(im);
  534.     im = pattern;
  535.     im.square_of(size,rowcol(0,0)) = -1;
  536.     im1 = im;
  537.     class SqrImage : public PixelPrimAction {
  538.       void operation(GRAY& pixel) { pixel = sqr((GRAY_SIGNED)pixel); }
  539.       public: SqrImage(void) {}
  540.     };
  541.     im1.apply(SqrImage());
  542.     assert( sum_over((Rectangle)im1) == im.norm_2_sqr() );
  543.   }
  544.   cout << "\tChecking out the 2. image norm is equal to the scalar product\n"
  545.           "\t\tof the image with itself\n";
  546.   assert( Test_image.norm_2_sqr() == Test_image * Test_image );
  547.   cout << "\tChecking out the inf image norm\n";
  548.   assert( Test_image.norm_inf() == 2*pattern );
  549.  
  550.   cout << "\nChecking out that the image is equal to itself\n"
  551.           "(according to norms)\n";
  552.   assert( norm_1(Test_image,Test_image) == 0 );
  553.   assert( norm_2_sqr(Test_image,Test_image) == 0 );
  554.   assert( norm_inf(Test_image,Test_image) == 0 );
  555.   
  556.   cout << "\nCheck the difference between the test images set as above"
  557.           "\nand the image with the uniform pattern\n";
  558.   IMAGE im1(Test_image);
  559.   im1 = pattern;
  560.  
  561.   cout << "\tVerify the identity ||im1-im2|| = ||im2-im1||\n";
  562.   assert( norm_1(Test_image,im1) == norm_1(im1,Test_image) );
  563.   assert( norm_2_sqr(Test_image,im1) == norm_2_sqr(im1,Test_image) );
  564.   assert( norm_inf(Test_image,im1) == norm_inf(im1,Test_image) );
  565.  
  566.   cout << "\tVerify the norm values\n";
  567.   assert( norm_1(Test_image,im1) == 3 * pattern * sqr(size) );
  568.   assert( norm_2_sqr(Test_image,im1) == sqr(3 * pattern) * sqr(size) );
  569.   assert( norm_inf(Test_image,im1) == 3 * pattern );
  570.   
  571.   cout << "\nDone\n\n";
  572. }
  573.  
  574.                 // Check out min/max finding operations
  575. static void test_image_extrema(void)
  576. {
  577.   const int pattern = 154;
  578.  
  579.   cout << "\n\nTest finding extremum pixel values and image normalization\n";
  580.  
  581.   {
  582.     cout << "\n\tExtrema of the zero image\n";
  583.     Test_image.clear();
  584.     Extrema extr(Test_image);
  585.     assert( extr.min() == 0 && extr.max() == 0 );
  586.   }
  587.  
  588.   {
  589.     cout << "\tInitializing the image with the pattern " << pattern << "\n";
  590.     Test_image = pattern;
  591.     Extrema extr(Test_image);
  592.     assert( extr.min() == pattern && extr.max() == pattern );
  593.   }
  594.  
  595.   {
  596.     cout << "\tSetting pixel (1,2) to 0\n";
  597.     Test_image(1,2) = 0;
  598.     Extrema extr(Test_image);
  599.     assert( extr.min() == 0 && extr.max() == pattern &&
  600.         extr.loc_min() == rowcol(1,2) );
  601.     assert( Test_image >= extr.min() && Test_image <= extr.max() );
  602.   }
  603.  
  604.   {
  605.     cout << "\tSetting pixel (2,1) to 2*pattern = " << 2*pattern << "\n";
  606.     Test_image(2,1) = 2*pattern;
  607.     Extrema extr(Test_image);
  608.     assert( extr.min() == 0 && extr.max() == 2*pattern &&
  609.         extr.loc_min() == rowcol(1,2) && extr.loc_max() == rowcol(2,1) );
  610.     assert( Test_image >= extr.min() && Test_image <= extr.max() );
  611.   }
  612.  
  613.   {
  614.     cout << "\tOffsetting by " << pattern << "\n";
  615.     Test_image -= pattern;
  616.     Extrema extr(Test_image);
  617.     assert( extr.min() == -pattern && extr.max() == pattern &&
  618.         extr.loc_min() == rowcol(1,2) && extr.loc_max() == rowcol(2,1) );
  619.     assert( Test_image >= extr.min() && Test_image <= extr.max() );
  620.   }
  621.  
  622.   {
  623.     cout << "\tOffsetting by " << 2*pattern << "\n";
  624.     Test_image -= 2*pattern;
  625.     Extrema extr(Test_image);
  626.     assert( extr.min() == -3*pattern && extr.max() == -pattern &&
  627.         extr.loc_min() == rowcol(1,2) && extr.loc_max() == rowcol(2,1) );
  628.     assert( Test_image >= extr.min() && Test_image <= extr.max() );
  629.   }
  630.  
  631.   cout << "\tNormalization ... \n";
  632.   Test_image = pattern;
  633.   Test_image.square_of(4,rowcol(2,1)) = -3*pattern;
  634.   Test_image.normalize_for_display();
  635.   Extrema extr(Test_image);
  636.   assert( extr.min() == 0 && extr.max() >= (1<<Test_image.q_depth())-2 );
  637.   assert( Test_image >= extr.min() && Test_image <= extr.max() );
  638.  
  639.   cout << "\nDone\n\n";
  640.  
  641. }
  642.  
  643.                 // Test the histogram equalization
  644. static void test_equalization(void)
  645. {
  646.   cout << "\n\nTest the histogram equalization\n";
  647.  
  648.   {
  649.     cout << "\tTest equalizing 16x16x8 full-gray scale image\n";
  650.     IMAGE full_gray(16,16,8);
  651.     register int i,j;
  652.     for(i=0; i<16; i++)
  653.       for(j=0; j<16; j++)
  654.     full_gray(i,j) = (i<<4) | j;
  655.     Extrema full_gray_extr(full_gray);
  656.     assert( full_gray_extr.min() == 0 && full_gray_extr.max() == 255 );
  657.  
  658.     full_gray.equalize(128);
  659.                     // After the equalization, the
  660.                     // image should have (almost) the
  661.                     // same span but have only even
  662.                     // pixel values
  663.     Extrema full_gray_extr_eq(full_gray);
  664.     assert( full_gray_extr_eq.min() == 0 && full_gray_extr_eq.max() == 254 );
  665.     for(i=0; i<16; i++)
  666.       for(j=0; j<16; j++)
  667.     assert( (full_gray(i,j) & 1) == 0 );
  668.   }
  669.  
  670.   {
  671.     cout << "\tAn image with a flat histogram should stay this way\n";
  672.     IMAGE test_im(16,16,8);
  673.     test_im.rectangle(rowcol(0,0),rowcol(15,3)) = 0;
  674.     test_im.rectangle(rowcol(0,4),rowcol(15,7)) = 80;
  675.     test_im.rectangle(rowcol(0,8),rowcol(15,11)) = 160;
  676.     test_im.rectangle(rowcol(0,12),rowcol(15,15)) = 255;
  677.  
  678.     test_im.equalize(128);
  679.  
  680.     IMAGE test_im_ethalon(test_im);
  681.     test_im_ethalon.rectangle(rowcol(0,0),rowcol(15,3)) = 31;
  682.     test_im_ethalon.rectangle(rowcol(0,4),rowcol(15,7)) = 94;
  683.     test_im_ethalon.rectangle(rowcol(0,8),rowcol(15,11)) = 158;
  684.     test_im_ethalon.rectangle(rowcol(0,12),rowcol(15,15)) = 222;
  685.  
  686.     assert( test_im == test_im_ethalon );
  687.   }
  688.  
  689. #if 0
  690.   {
  691.     cout << "\tTest equalizing of uneven histogram\n";
  692.     IMAGE test_im(16,16,4);
  693.     test_im = 8;            // Make a stripy image
  694.     register int i,j;            // with very uneven histogram
  695.     for(i=0; i<8; i++)            // (large peak at value 8)
  696.       for(j=0; j<16; j++)
  697.     test_im(i,j) = j;
  698.  
  699.     test_im.print("before");
  700.     test_im.equalize(16);
  701.     test_im.print("after");
  702.   }
  703. #endif
  704.  
  705.   cout << "\nDone\n\n";
  706. }
  707.  
  708.  
  709.                 // Test expand/shrink operations
  710. static void test_expand_shrink()
  711. {
  712.   const int pattern = 154;
  713.  
  714.   cout << "\n\nTest shrink/expand image operations\n";
  715.  
  716.   {
  717.     cout << "\tExpansion/shrinking of the uniform image\n";
  718.     Test_image = pattern;
  719.     IMAGE blown_out(IMAGE::Expand,Test_image);
  720.     assert( blown_out.q_nrows() == 2*Test_image.q_nrows() );
  721.     assert( blown_out.q_ncols() == 2*Test_image.q_ncols() );
  722.     assert( blown_out.q_depth() == Test_image.q_depth() );
  723.     assert( blown_out == pattern );
  724.     IMAGE blown_shrunk(IMAGE::Shrink,blown_out);
  725.     assert( blown_shrunk == Test_image );
  726.  
  727.     {
  728.       IMAGE im(Test_image);
  729.       im.coerce(Test_image);
  730.       assert( im == Test_image );
  731.     }
  732.     
  733.     {
  734.       IMAGE im(Test_image.q_nrows()+1,Test_image.q_ncols()/2-1,
  735.            Test_image.q_depth());
  736.       im.coerce(Test_image);
  737.       verify_pixel_value(im,pattern);
  738.     }
  739.     
  740.     {
  741.       IMAGE im(Test_image.q_nrows()/3,Test_image.q_ncols()*2,
  742.            Test_image.q_depth());
  743.       im.coerce(Test_image);
  744.       verify_pixel_value(im,pattern);
  745.     }
  746.     
  747.   }
  748.  
  749.   {
  750.     cout << "\tExpansion of the uniform image with a small stain\n";
  751.     Test_image = pattern;
  752.     Test_image(0,0) = 1;
  753.     Test_image(1,1) = 0;
  754.     IMAGE blown_out(IMAGE::Expand,Test_image);
  755.     assert( blown_out(1,1) == 1 );
  756.     assert( blown_out(3,3) == 0 );
  757.     class BlowImage : public LazyImage
  758.     {
  759.       const IMAGE& orig_image;
  760.       void fill_in(IMAGE& im) const
  761.       {
  762.     for(register int i=0; i<im.q_nrows(); i++)
  763.       for(register int j=0; j<im.q_ncols(); j++)
  764.         im(i,j) = orig_image(i/2,j/2);
  765.       }
  766.     public:
  767.       BlowImage(const IMAGE& image) : 
  768.     LazyImage(2*image.q_nrows(),2*image.q_ncols(),image.q_depth()),
  769.         orig_image(image) {}
  770.     };
  771.     IMAGE another_blown_out = BlowImage(Test_image);
  772.     assert( another_blown_out == blown_out );
  773.     IMAGE yet_another_blown_out(another_blown_out);
  774.     yet_another_blown_out.clear();
  775.     yet_another_blown_out.coerce(Test_image);
  776.     assert( yet_another_blown_out == blown_out );
  777.     IMAGE blown_shrunk(IMAGE::Shrink,blown_out);
  778.     assert( blown_shrunk == Test_image );
  779.     blown_out.square_of(2,rowcol(0,0)) += pattern - 1;
  780.     blown_out.square_of(2,rowcol(2,2)) += pattern;
  781.     assert( blown_out == pattern );
  782.   }
  783.   {
  784.     cout << "\tShrinking the uniform image with small stains\n";
  785.     Test_image = pattern;
  786.     Test_image.square_of(2,rowcol(0,0)) = 1; Test_image(0,0) = 0;
  787.     Test_image.square_of(2,rowcol(2,0)) = 5; Test_image(3,1) = 0;
  788.     Test_image.square_of(2,rowcol(0,2)) = 0; Test_image(0,2) = 1;
  789.     Test_image.square_of(2,rowcol(0,4)) = 0; Test_image(1,5) = 7;
  790.     Test_image.square_of(2,rowcol(2,2)) = 1; 
  791.     Test_image(2,2) = 0; Test_image(3,3) = 0;
  792.  
  793.     IMAGE shrunk(IMAGE::Shrink,Test_image);
  794.     assert( shrunk(0,0) == 1 );
  795.     assert( shrunk(0,1) == 0 );
  796.     shrunk(0,0) += pattern - 1;
  797.     shrunk(1,0) += pattern - 4;
  798.     shrunk(0,1) += pattern;
  799.     shrunk(0,2) += pattern - 2;
  800.     shrunk(1,1) += pattern - 1;
  801.     assert( shrunk == pattern );
  802.   }
  803.   {
  804.     cout << "\tStretching/shrinking an image with vertical stripes\n";
  805.     class MakeVStripes : public PixelAction
  806.     {
  807.       GRAY pattern;
  808.       void operation(GRAY& pixel) { pixel = col & 1 ? pattern : 0; }
  809.       public: MakeVStripes(const GRAY _p) : pattern(_p) {}
  810.     };
  811.     Test_image.apply(MakeVStripes(pattern));
  812.     IMAGE shrunk(Test_image.q_nrows()/3+1,
  813.          Test_image.q_ncols()/2,Test_image.q_depth());
  814.     shrunk.coerce(Test_image);
  815.     verify_pixel_value(shrunk,pattern);
  816.     IMAGE vert_shrunk(Test_image.q_nrows()/3-1,
  817.               Test_image.q_ncols(),Test_image.q_depth());
  818.     vert_shrunk.coerce(Test_image);
  819.     assert( Test_image.rectangle(rowcol(0,0),
  820.                  rowcol(Test_image.q_nrows()/3-2,
  821.                     Test_image.q_ncols()-1))
  822.         == vert_shrunk );
  823.     IMAGE vert_stretched(Test_image.q_nrows()+7,
  824.              Test_image.q_ncols(),Test_image.q_depth());
  825.     vert_stretched.coerce(Test_image);
  826.     assert( vert_stretched.rectangle(rowcol(0,0),
  827.                      rowcol(Test_image.q_nrows()-1,
  828.                     Test_image.q_ncols()-1))
  829.         == Test_image );
  830.   }
  831.  
  832.   {
  833.     cout << "\tStretching/shrinking an image with horizontal stripes\n";
  834.     class MakeHStripes : public PixelAction
  835.     {
  836.       GRAY pattern;
  837.       void operation(GRAY& pixel) { pixel = row & 1 ? pattern : 0; }
  838.       public: MakeHStripes(const GRAY _p) : pattern(_p) {}
  839.     };
  840.     Test_image.apply(MakeHStripes(pattern));
  841.     IMAGE shrunk(Test_image.q_nrows()/2,
  842.          Test_image.q_ncols()+7,Test_image.q_depth());
  843.     shrunk.coerce(Test_image);
  844.     verify_pixel_value(shrunk,pattern);
  845.     IMAGE hor_shrunk(Test_image.q_nrows(),
  846.              Test_image.q_ncols()/3-1,Test_image.q_depth());
  847.     hor_shrunk.coerce(Test_image);
  848.     assert( Test_image.rectangle(rowcol(0,0),
  849.                  rowcol(Test_image.q_nrows()-1,
  850.                     Test_image.q_ncols()/3-2))
  851.         == hor_shrunk );
  852.     IMAGE hor_stretched(Test_image.q_nrows(),
  853.             Test_image.q_ncols()+9,Test_image.q_depth());
  854.     hor_stretched.coerce(Test_image);
  855.     assert( hor_stretched.rectangle(rowcol(0,0),
  856.                     rowcol(Test_image.q_nrows()-1,
  857.                        Test_image.q_ncols()-1))
  858.         == Test_image );
  859.   }
  860.  
  861.   cout << "\nDone\n";
  862. }
  863.  
  864. /*
  865.  *------------------------------------------------------------------------
  866.  *            The testing routing module
  867.  */
  868.  
  869. main()
  870. {
  871.   test_primitive();
  872.   test_rowcol();
  873.   test_pixel_op();
  874.   test_image_op();
  875.  
  876.   test_scalar_product();
  877.   test_image_norms();
  878.   test_image_extrema();
  879.  
  880.   test_equalization();
  881.   test_expand_shrink();
  882. }
  883.  
  884.